//namespace serika
//{
	namespace db
	{
		// CREATE Functions
		//////////////////////////////////////////////////////////////////////////
		template<typename TYPE>
		TYPE* RecordBase::Create(db::FieldMap *fieldMap, bool throwOnError)
		{
			TYPE* obj = new TYPE(fieldMap);
			obj->Save(throwOnError);
			return obj;
		}
	
		template<typename TYPE>
		bool RecordBase::Create(std::vector<TYPE*>& results, std::vector<FieldMap*>& fieldMaps, bool throwOnError /* = false */)
		{
			if (fieldMaps.empty())
			{
				return true;
			}
	
			bool ret = true;
			std::vector<TYPE*> goodResults;
			std::vector<FieldMap*> fms;
	
			for (std::vector<FieldMap*>::iterator itr = fieldMaps.begin(); itr != fieldMaps.end(); ++itr)
			{
				TYPE* obj = new TYPE(*itr);
				obj->Validate();
				if (!obj->GetErrorSet().IsEmpty())
				{
					ret = false;
				}
				else
				{
					obj->BeforeSave();
					obj->BeforeCreate();
					fms.push_back(*itr);
					goodResults.push_back(obj);
				}
				results.push_back(obj);
			}
			try
			{
				ret = TYPE::mAdapter->CreateRecords(fms, TYPE::GetTableName(), TYPE::GetPrimaryKey());
			}
			catch (RecordException& e)
			{
				if (throwOnError)
				{
					throw e;
				}
				return false;
			}
	
			if (ret)
			{
				for (typename std::vector<TYPE*>::iterator itr = goodResults.begin(); itr != goodResults.end(); ++itr)
				{
					TYPE* obj = *itr;
					obj->AfterCreate();
					obj->AfterSave();
				}
			}
			else if (throwOnError)
			{
				throw RecordException(-1, _T("Failed on saving"));
			}
			return ret;
		}
	
		// SELECT Functions
		//////////////////////////////////////////////////////////////////////////
		template<typename TYPE>
		TYPE* RecordBase::Find(int id)
		{
			const std::string& tableName = TYPE::GetTableName();
			//if (TYPE::IsCachable())
			//{
			//	FieldMap* res = mCache.GetRecord(tableName, id);		// Read from cache first
			//	if (res != 0)	// Hit
			//	{
			//		return new TYPE(res, false);
			//	}
			//}
	
			// Not hit
			std::string conditions = TYPE::mAdapter->ConstructIdConditions(id);
			std::vector<FieldMap*> rs;
			int i = TYPE::mAdapter->ReadRecords(rs,tableName, conditions, 0, 1, "*", "", "", "", "");	// Read from db
			if (i == 1)
			{	// Found
				TYPE* obj = new TYPE((FieldMap*)rs[0], false);
				//if (TYPE::IsCachable())		// Set to cache
				//{
				//	int id = obj->GetRawValue<int>("id");
				//	mCache.SetRecord(tableName, id, *rs[0]);
				//}
				return obj;
			}
			else
			{	// Error! Clean up
				for (std::vector<FieldMap*>::iterator itr = rs.begin(); itr != rs.end(); ++itr)
				{
					delete (*itr);
				}
				return 0;
			}
		}
	
		template<typename TYPE>
		TYPE* RecordBase::Find(const Any& value, const std::string& column)
		{
			std::string conditions;
			if (column.empty())
			{
				conditions = TYPE::mAdapter->ConstructConditions(TYPE::GetPrimaryKey(), value);
			}
			else
			{
				conditions = TYPE::mAdapter->ConstructConditions(column, value);
			}
			return RecordBase::FindFirst<TYPE>(conditions);
		}
	
		template<typename TYPE>
		int RecordBase::Find(std::vector<TYPE*>& resultSet, const std::vector<int>& ids)
		{
			const std::string& tableName = TYPE::GetTableName();
			const std::vector<int>* realIds = &ids;
			std::vector<int> tmpIds;
			//if (TYPE::IsCachable())
			//{
			//	for (std::vector<int>::const_iterator itr = ids.begin(); itr != ids.end(); ++itr)
			//	{
			//		FieldMap* res = mCache.GetRecord(tableName, *itr);		// Read from cache first
			//		if (res != 0)		// Hit. Add to the result set
			//		{
			//			resultSet.push_back(new TYPE(res, false));
			//		}
			//		else				// Not hit. We need to find it from db
			//		{
			//			tmpIds.push_back(*itr);
			//		}
			//	}
			//	realIds = &tmpIds;
			//}
	
			if (realIds->empty())
			{
				return resultSet.size();
			}
	
			std::string conditions = TYPE::mAdapter->ConstructIdConditions(*realIds);
			std::vector<FieldMap*> rs;
			int num = TYPE::mAdapter->ReadRecords(rs,tableName, conditions, 0, 0, "*", "", "", "", "");	// Read from db
			rs.reserve(num);
	
			for (std::vector<FieldMap*>::iterator itr = rs.begin(); itr != rs.end(); ++itr)
			{
				FieldMap* fields = *itr;
				TYPE* obj = new TYPE(fields, false);
				//if (TYPE::IsCachable())
				//{
				//	mCache.SetRecord(tableName, obj->GetRawValue<int>("id"), *fields);		// Set to cache
				//}
				resultSet.push_back(obj);			// Push the object to the result set
			}
			return resultSet.size();
		}
	
		template<typename TYPE>
		int RecordBase::Find(std::vector<TYPE*>& resultSet, const std::vector<Any>& values, const std::string& column)
		{
			std::string conditions;
			if (column.empty())
			{
				conditions = TYPE::mAdapter->ConstructConditions(TYPE::GetPrimaryKey(), values);
			}
			else
			{
				conditions = TYPE::mAdapter->ConstructConditions(column, values);
			}
			return RecordBase::FindAll<TYPE>(resultSet, conditions);
		}
	
		template<typename TYPE>
		TYPE* RecordBase::FindFirst(
									const std::string& conditions,
									const std::string& select,
									const std::string& joins,
									const std::string& order,
									const std::string& group,
									const std::string& having)
		{
			const std::string& tableName = TYPE::GetTableName();
			bool readOnly = !select.empty() && select != "*";
			std::vector<FieldMap*> rs;
			std::string statement = TYPE::mAdapter->ConstructSelect(tableName, conditions, 0, 1, 
				select, joins, order, group, having);
			//if (TYPE::IsCachable() && mCache.GetRecords(rs, tableName, statement))		// Read from cache
			//{	// Hit
			//	return new TYPE(rs[0], readOnly);
			//}
	
			// Not hit
			int i = TYPE::mAdapter->ReadRecords(rs, TYPE::GetTableName(), conditions, 0, 1, select, joins, order, group, having);
			if (i == 1)
			{
				TYPE* obj = new TYPE((FieldMap*)rs[0], readOnly);
				//if (TYPE::IsCachable())
				//{
				//	mCache.SetRecords(tableName, statement, rs);
				//	if (!readOnly)
				//	{
				//		try
				//		{
				//			int id = obj->GetRawValue<int>("id");
				//			mCache.SetRecord(tableName, id, *rs[0]);
				//		}
				//		catch (RecordException) { }
				//	}
				//}
				return obj;
			}
			else
			{
				for (std::vector<FieldMap*>::iterator itr = rs.begin(); itr != rs.end(); ++itr)
				{
					delete (*itr);
				}
				return 0;
			}
		}
	
		template<typename TYPE>
		int RecordBase::FindAll(
								std::vector<TYPE*>& resultSet,
								const std::string& conditions,
								int offset,
								int limit,
								const std::string& select,
								const std::string& joins,
								const std::string& order,
								const std::string& group,
								const std::string& having)
		{
			resultSet.clear();
			const std::string& tableName = TYPE::GetTableName();
			bool readOnly = !select.empty() && select != "*" || !joins.empty();
			std::string statement = TYPE::mAdapter->ConstructSelect(tableName, conditions, offset, limit, select, joins, order, group, having);
			std::vector<FieldMap*> rs;
	
			//if (TYPE::IsCachable() && mCache.GetRecords(rs, tableName, statement))		// Read from cache
			//{	// Hit
			//	for (std::vector<FieldMap*>::iterator itr = rs.begin(); itr != rs.end(); ++itr)
			//	{
			//		resultSet.push_back(new TYPE(*itr, readOnly));
			//	}
			//	return resultSet.size();
			//}
	
			// Not hit
			int num = TYPE::mAdapter->ReadRecords(rs, tableName, conditions, offset, limit, select, joins, order, group, having);
			//if (TYPE::IsCachable())
			//{
			//	mCache.SetRecords(tableName, statement, rs);		// Set to cache
			//}
			resultSet.reserve(num);
			for (std::vector<FieldMap*>::iterator itr = rs.begin(); itr != rs.end(); ++itr)
			{
				resultSet.push_back(new TYPE(*itr, readOnly));
			}
			return num;
		}
	
		template<typename TYPE>
		int RecordBase::Count(const std::string &column, const std::string &conditions, const std::string &joins)
		{
			return TYPE::mAdapter->Count(TYPE::GetTableName(), column, conditions, joins);
		}
	
		template<typename TYPE>
		Pagination<TYPE>* RecordBase::Paginate(int page, int perPage, const std::string &conditions, 
											   const std::string &select, const std::string &joins, const std::string &order)
		{
			int count = RecordBase::Count<TYPE>("*", conditions, joins);
			--page;
	
			Pagination<TYPE>* pagination = new Pagination<TYPE>;
			pagination->mPageCount = (count % perPage) ? count / perPage + 1 : count / perPage;
			pagination->mCurrentPage = page + 1;
	
			if (count < page * perPage || perPage < 0)		// No Result
			{
				return pagination;
			}
	
			RecordBase::FindAll<TYPE>(pagination->mResultSet, conditions, page * perPage, perPage, select, joins, order);
	
			return pagination;
		}
	
		// UPDATE functions
		/////////////////////////////////////////////////////////////////////////
		template<typename TYPE>
		int RecordBase::UpdateAll(const std::string& settings, const std::string& conditions)
		{
			int num = TYPE::mAdapter->UpdateAllRecords(settings, conditions, TYPE::GetTableName());
			//if (TYPE::IsCachable() && num > 0)
			//{
			//	mCache.ExpireAll(TYPE::GetTableName());
			//}
			return num;
		}
	
		// DELETE functions
		/////////////////////////////////////////////////////////////////////////
		template<typename TYPE>
		bool RecordBase::Delete(int id)
		{
			std::string conditions = TYPE::mAdapter->ConstructIdConditions(id);
			int num = TYPE::mAdapter->DeleteRecord(conditions, TYPE::GetTableName());
			//if (num > 0 && TYPE::IsCachable())
			//{
			//	mCache.ExpireOne(TYPE::GetTableName(), id);		// Expire relative record
			//}
	
			return num > 0;
		}
	
		template<typename TYPE>
		int RecordBase::Delete(const Any& value, const std::string& column)
		{
			std::string conditions;
			if (column.empty())
			{
				conditions = TYPE::mAdapter->ConstructConditions(TYPE::GetPrimaryKey(), value);
			}
			else
			{
				conditions = TYPE::mAdapter->ConstructConditions(column, value);
			}
	
			int num = TYPE::mAdapter->DeleteRecord(conditions, TYPE::GetTableName());
			//if (num > 0 && TYPE::IsCachable())
			//{
			//	mCache.ExpireAll(TYPE::GetTableName());
			//}
	
			return num;
		}
	
		template<typename TYPE>
		int RecordBase::Delete(const std::vector<Any>& values, const std::string& column)
		{
			std::string conditions;
			if (column.empty())
			{
				conditions = TYPE::mAdapter->ConstructConditions(TYPE::GetPrimaryKey(), values);
			}
			else
			{
				conditions = TYPE::mAdapter->ConstructConditions(column, values);
			}
	
			int num = TYPE::mAdapter->DeleteRecord(conditions, TYPE::GetTableName());
			//if (num > 0 && TYPE::IsCachable())
			//{
			//	mCache.ExpireAll(TYPE::GetTableName());
			//}
	
			return num;
		}
	
		template<typename TYPE>
		int RecordBase::DeleteAll(const std::string& conditions)
		{
			int num = TYPE::mAdapter->DeleteRecord(conditions, TYPE::GetTableName());
			//if (num > 0 && TYPE::IsCachable())
			//{
			//	mCache.ExpireAll(TYPE::GetTableName());
			//}
	
			return num;
		}
	
		template<typename TYPE>
		int RecordBase::Destroy(const Any& value, const std::string& column)
		{
			std::string conditions;
			if (column.empty())
			{
				conditions = TYPE::mAdapter->ConstructConditions(TYPE::GetPrimaryKey(), value);
			}
			else
			{
				conditions = TYPE::mAdapter->ConstructConditions(column, value);
			}
			return RecordBase::DestroyAll<TYPE>(conditions);
		}
	
		template<typename TYPE>
		int RecordBase::Destroy(const std::vector<Any>& values, const std::string& column)
		{
			std::string conditions;
			if (column.empty())
			{
				conditions = TYPE::mAdapter->ConstructConditions(TYPE::GetPrimaryKey(), values);
			}
			else
			{
				conditions = TYPE::mAdapter->ConstructConditions(column, values);
			}
			return RecordBase::DestroyAll<TYPE>(conditions);
		}
	
		template<typename TYPE>
		int RecordBase::DestroyAll(const std::string& conditions)
		{
			std::vector<TYPE*> rs;
			int num = RecordBase::FindAll<TYPE>(rs, conditions);
			for (typename std::vector<TYPE*>::iterator itr = rs.begin(); itr != rs.end(); ++itr)
			{
				TYPE* obj = *itr;
				obj->Destroy();
				delete obj;
			}
			return num;
		}
	
		template<typename TYPE>
		bool RecordBase::EstablishConnection(
											 int concurrency,
											 const std::string& adapterName, 
											 const std::string& database,
											 const std::string& username,
											 const std::string& password,
											 const std::string& host,
											 int port,
											 int timeout,
											 const std::string& encoding)
		{
			//TYPE::mAdapter = Adapter::Create(concurrency, adapterName, database, username, password, host, port, timeout, encoding);
			return true;
		}
	
		template<typename TYPE>
		void RecordBase::CloseConnection()
		{
			TYPE::mAdapter->Destroy();
			TYPE::mAdapter = RecordBase::mNullAdapter;
		}
	
		template<typename TYPE>
		bool RecordBase::SetRecordAdapter(size_t adapterIndex)
		{
			if (adapterIndex >= mAdapters.size())
			{
				return false;
			}
			TYPE::mAdapter = mAdapters[adapterIndex];
			return true;
		}
	
		template<typename TYPE>
		const TYPE& RecordBase::GetRawValue(const std::string& name) const
		{
			if (mFields == 0)
			{
				throw RecordException(-1, _T("No content in record"));
			}
	
			FieldMap::iterator itr = mFields->find(name);
			if (itr == mFields->end())
			{
				throw RecordException(-1, _T("No such field"));
			}
	
			return itr->second.Get<TYPE>();
		}
	}
//}
